using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Ideopuzzle.Effects;
using Ideopuzzle.Resources;


namespace Ideopuzzle
{
    public class GameBoard : DrawableGameComponent
    {
        #region Fields

        public static readonly int ROWS_NUMBER = 7;
        public static readonly int COLS_NUMBER = 7;
        public static readonly Vector2 NW_BOARD_COORD = new Vector2(192,23);
        public static readonly Vector2 SE_BOARD_COORD = new Vector2(606, 437);
        public static readonly int CELL_DIM = 59;
        public static readonly int LEVEL_UP_MULTIPLIER = 1000;

        private ExplosionComponent explosions;
        private AudioManager audio_manager;
        private IInputManager input_manager;
        private SpriteBatch sprite_batch;
        private SpriteFont font36, font72, font14;
        private Texture2D timebar, timebarborder_l, timebarborder_r;
        private Random random;

        private List<RotationPoint> rotation_points;
        private List<Tile> tiles_to_draw, near_tiles = new List<Tile>(10);
        private Tile[,] tiles;
        private Cursor cursor;
        private Rectangle board_bound, dominant_tile_rect = new Rectangle(55, 192, 81, 81), pause_rect = new Rectangle(720, 12, 80, 40);
        private Rectangle resume_rect, exit_rect, new_rect;
        private Vector2 resume_pos, exit_pos, new_pos;

        private float[] dominances;
        private float game_timer, MAX_TIME, level_up_fade_timer = 0, chain_fade_timer = 0, score_timer = 0, chain_timer, conversion_timer = 0;
        private int score, current_level = 1, current_dominance = 0, difficulty = 0, current_score = 0;
        private bool level_up = false, chain = false, pause = false, game_over = false;
        //private List<List<Gem>> combo_list = new List<List<Gem>>(5);
        private int[] high_scores;        

        #endregion

        public GameBoard(Game game)
            : base(game)
        {
            tiles = new Tile[ROWS_NUMBER,COLS_NUMBER];
            tiles_to_draw = new List<Tile>();
            rotation_points = new List<RotationPoint>();

            board_bound = new Rectangle((int)NW_BOARD_COORD.X, (int)NW_BOARD_COORD.Y,
                (int)(SE_BOARD_COORD.X - NW_BOARD_COORD.X), (int)(SE_BOARD_COORD.Y - NW_BOARD_COORD.Y));

            random = new Random(DateTime.Now.Millisecond);

            switch (Options.DifficultyLevel)
            {
                case Difficulty.Easy: MAX_TIME = 90; break;
                case Difficulty.Medium: MAX_TIME = 60; break;
                case Difficulty.Hard: MAX_TIME = 45; break;
                case Difficulty.VeryHard: MAX_TIME = 30; break;
            }

            difficulty = (int)Options.DifficultyLevel + 1;

            game_timer = MAX_TIME;
        }

        public override void Initialize()
        {
            sprite_batch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
            input_manager = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            input_manager.OnTap += new InputManager.Tap(OnTap);

            explosions = new ExplosionComponent(Game);
            Game.Components.Add(explosions);

            dominances = new float[8];

            base.Initialize();
        }

        protected override void LoadContent()
        {
            audio_manager = Game.Services.GetService(typeof(AudioManager)) as AudioManager;

            GenerateLevelTiles();
            GenerateRotationPoint();

            cursor = new Cursor(sprite_batch, Vector2.One * (-500),
                Game.Content.Load<Texture2D>("Textures/Game/gamecursorandarrows"));

            timebar = Game.Content.Load<Texture2D>("Textures/Game/gametimebar");
            timebarborder_l = Game.Content.Load<Texture2D>("Textures/Game/gametimebarborder_l");
            timebarborder_r = Game.Content.Load<Texture2D>("Textures/Game/gametimebarborder_r");
            font36 = Game.Content.Load<SpriteFont>("Fonts/Light36");
            font72 = Game.Content.Load<SpriteFont>("Fonts/Light72");
            font14 = Game.Content.Load<SpriteFont>("Fonts/Regular14");

            resume_pos = new Vector2(GraphicsDevice.Viewport.Width / 2.0f - font36.MeasureString(Lang.Game_Resume).X - 20, 245);
            resume_rect = new Rectangle((int)resume_pos.X, (int)resume_pos.Y, (int)font36.MeasureString(Lang.Game_Resume).X, 
                (int)font36.MeasureString(Lang.Game_Resume).Y);

            exit_pos = new Vector2(GraphicsDevice.Viewport.Width / 2.0f + 20, 245);
            exit_rect = new Rectangle((int)exit_pos.X, (int)exit_pos.Y, (int)font36.MeasureString(Lang.Game_Exit).X,
                (int)font36.MeasureString(Lang.Game_Exit).Y);

            new_pos = new Vector2(GraphicsDevice.Viewport.Width / 2.0f - font36.MeasureString(Lang.Game_New).X - 20, 245);
            new_rect = new Rectangle((int)new_pos.X, (int)new_pos.Y, (int)font36.MeasureString(Lang.Game_New).X,
                (int)font36.MeasureString(Lang.Game_New).Y);

            high_scores = new int[3];

            MediaPlayer.MediaStateChanged += new EventHandler<EventArgs>(MediaStateChanged);

            base.LoadContent();

            audio_manager.PlayGingle();
        }

        public override void Update(GameTime gameTime)
        {
            var dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (!game_over && !pause)
            {
                game_timer = MathHelper.Clamp(game_timer - dt, 0, MAX_TIME);
                for (int i = 0; i < dominances.Length; i++)
                    dominances[i] = Math.Max(0, dominances[i] - (dt / 0.5f));

                chain_timer = Math.Max(0, chain_timer - dt);

                score_timer = Math.Max(0, score_timer - dt);

                if (dominances[current_dominance] > 7)                
                    if (conversion_timer <= 0)
                    {
                        var f = false; var y = 0; var x = 0;

                        for (int i = 0; i < 5; i++)
                        {
                            x = random.Next(ROWS_NUMBER); y = random.Next(COLS_NUMBER);

                            f = tiles[x, y].ConvertTile(Game.Content.Load<Texture2D>("Textures/Game/Tiles/" + current_dominance),
                                current_dominance);

                            if (f) break;
                        }

                        if (f)
                        {
                            explosions.AddExplosion(tiles[x, y].Position, ExplosionType.Short);
                            conversion_timer = 1.2f;
                        }
                    }
                    else   
                        conversion_timer = Math.Max(0, conversion_timer - dt);
            }

            if (game_timer <= 0)
            {
                game_over = true;
            }
            else
            {

                if (chain_timer < 0.5f)
                {
                    chain_fade_timer -= dt;
                    if (chain_fade_timer <= 0)
                        chain = false;
                }
                else if (!chain)
                {
                    chain = true;
                    chain_fade_timer = 3.0f;
                }

                if (level_up)
                {
                    level_up_fade_timer -= dt;
                    if (level_up_fade_timer <= 0.0f)
                        level_up = false;
                }

                if (score > current_level * LEVEL_UP_MULTIPLIER)
                {
                    level_up = true;
                    level_up_fade_timer = 2.0f;
                    current_level++;
                }

                if (score_timer <= 0) CheckAndManageHighScores();

                CheckBoardComb();
            }

            base.Update(gameTime);
        }

        private void OnTap(Vector2 tposition)
        {
            var p = new Point((int)tposition.X, (int)tposition.Y);

            if (pause)
            {
                if (resume_rect.Contains(p) || input_manager.IsBackButtonPressed())
                {
                    pause = false;
                    audio_manager.PlayClick();
                }
                else if (exit_rect.Contains(p))
                {
                    audio_manager.StopGingle();
                    ScreenManager.SelectMainMenu(Game);
                    audio_manager.PlayClick();
                }
                return;
            }

            else if (game_over)
            {
                if (new_rect.Contains(p))
                {
                    ScreenManager.StartLevel(Game);
                    audio_manager.PlayClick();
                }
                else if (exit_rect.Contains(p) || input_manager.IsBackButtonPressed())
                {
                    audio_manager.StopGingle();
                    ScreenManager.SelectMainMenu(Game);
                    audio_manager.PlayClick();
                }
                return;
            }

            else if (board_bound.Contains(p))
            {
                int index = FindNearestRotationPoint(tposition);

                cursor.ChangePosition(rotation_points[index].Position);
                RotateTiles(index);

                audio_manager.PlaySwitch();
            }
            else if (pause_rect.Contains(p) || input_manager.IsBackButtonPressed())
            {
                pause = true;
                audio_manager.PlayClick();
            }
        }

        private void IntegrityCheck()
        {
            for (int i = 0; i < ROWS_NUMBER; i++)
            {
                for (int j = 0; j < COLS_NUMBER; j++)
                {
                    tiles[i, j].Picked = false;
                    if (tiles[i, j].PosOnBoard == tiles[i, j].DestinationOnBoard && 
                        (tiles[i, j].PosOnBoard.X != i || tiles[i, j].PosOnBoard.Y != j)
                        && !tiles[i, j].Moving && !tiles[i, j].Exploded)
                    {
                        tiles[i, j].DropTo(new Vector2(NW_BOARD_COORD.X + CELL_DIM * tiles[i,j].DestinationOnBoard.X,
                            NW_BOARD_COORD.Y + CELL_DIM * tiles[i, j].DestinationOnBoard.Y), 
                            tiles[i, j].DestinationOnBoard);
                    }
                }
            }
        }

        private float trial_alpha = 0.0f;
        public override void Draw(GameTime gameTime)
        {
            sprite_batch.Begin();

            for (int i = 0; i < tiles_to_draw.Count; i++)
                tiles_to_draw[i].DrawGem(gameTime);

            cursor.Draw(gameTime);

            if (chain)
            {
                sprite_batch.Draw(Game.Content.Load<Texture2D>("Textures/Game/gamechain"), 
                    Vector2.Zero, Color.White * chain_fade_timer);
            }

            if (dominances[current_dominance] > 5.0f)
            {
                var a = (float)((Math.Sin(gameTime.TotalGameTime.TotalSeconds * 5.0f) + 1) * 0.5f);
                a = a + 0.5f * (1 - a);

                sprite_batch.Draw(Game.Content.Load<Texture2D>("Textures/Game/Tiles/" + current_dominance),
                    dominant_tile_rect, Color.White * a);
            }

            if (level_up && !game_over)
            {
                sprite_batch.Draw(Game.Content.Load<Texture2D>("Textures/Game/gamelevelup"),
                    Vector2.Zero, Color.White * level_up_fade_timer);
                #region LEVEL UP STRING DRAW
                //var lev_up_str = "LEVEL UP!";
                //sprite_batch.DrawString(font36, lev_up_str, new Vector2(GraphicsDevice.Viewport.Width / 2.0f - 
                //    font36.MeasureString(lev_up_str).X / 2.0f, 190), Color.White * level_up_fade_timer);
                #endregion
            }

            sprite_batch.DrawString(font72, current_level.ToString(), new Vector2(85,34), Color.White, 
                0, Vector2.Zero, 0.8f, SpriteEffects.None, 0);

            sprite_batch.DrawString(font36, score.ToString(), new Vector2(80, 120), Color.White, 0, Vector2.Zero, 
                0.8f, SpriteEffects.None, 0);

            if (high_scores[0] > 0) sprite_batch.DrawString(font36, high_scores[0].ToString(), new Vector2(660, 75), Color.White, 
                0, Vector2.Zero, 0.8f, SpriteEffects.None, 0);
            if (high_scores[1] > 0) sprite_batch.DrawString(font36, high_scores[1].ToString(), new Vector2(660, 118), Color.White, 
                0, Vector2.Zero, 0.8f, SpriteEffects.None, 0);
            if (high_scores[2] > 0) sprite_batch.DrawString(font36, high_scores[2].ToString(), new Vector2(660, 161), Color.White, 
                0, Vector2.Zero, 0.8f, SpriteEffects.None, 0);

            var min = (int)game_timer / 60;
            var sec = (int)game_timer % 60;

            sprite_batch.DrawString(font14, "- " + min + " : " + sec, new Vector2(182, 448), new Color(37, 160, 218));
            sprite_batch.DrawString(font14, "- " + min + " : " + sec, new Vector2(181, 447), Color.White);

            if (game_timer > 0)
            {
                var width = (int)(timebar.Width * (game_timer / MAX_TIME));

                sprite_batch.Draw(timebarborder_l, new Vector2(237, 452), Color.White);
                sprite_batch.Draw(timebar, new Vector2(246, 452),
                    new Rectangle(0, 0, width, timebar.Height), Color.White);
                sprite_batch.Draw(timebarborder_r, new Vector2(246 + width, 452), Color.White);
                sprite_batch.Draw(timebarborder_r, new Vector2(246 + width, 452), Color.White);
            }
            else
            {
                sprite_batch.Draw(Game.Content.Load<Texture2D>("Textures/Game/gameover"), Vector2.Zero, Color.White);
                sprite_batch.DrawString(font36, Lang.Game_New, new_pos, new Color(139, 192, 63));
                sprite_batch.DrawString(font36, Lang.Game_Exit, exit_pos, new Color(230, 30, 38));
            }

            if (pause)
            {
                sprite_batch.Draw(Game.Content.Load<Texture2D>("Textures/Game/gamepause"), Vector2.Zero, Color.White);
                sprite_batch.DrawString(font36, Lang.UI_Pause, new Vector2(GraphicsDevice.Viewport.Width / 2.0f -
                    font36.MeasureString(Lang.UI_Pause).X / 2.0f, 190), Color.White);
                sprite_batch.DrawString(font36, Lang.Game_Resume, resume_pos, new Color(139, 192, 63));
                sprite_batch.DrawString(font36, Lang.Game_Exit, exit_pos, new Color(230, 30, 38));
            }

            if (GIdeopuzzle.IsTrial)
            {
                trial_alpha = (1.0f + ((float)Math.Sin(gameTime.TotalGameTime.TotalSeconds * 4.0f))) / 2.0f;

                sprite_batch.DrawString(font14, Lang.Trial, new Vector2(42, GraphicsDevice.Viewport.Height - 28), Color.Red * trial_alpha);
                sprite_batch.DrawString(font14, Lang.Trial, new Vector2(40, GraphicsDevice.Viewport.Height - 30), Color.White * trial_alpha);

                sprite_batch.DrawString(font14, Lang.Trial, new Vector2(GraphicsDevice.Viewport.Width - font14.MeasureString(Lang.Trial).X - 42,
                    GraphicsDevice.Viewport.Height - 28), Color.Red * trial_alpha);
                sprite_batch.DrawString(font14, Lang.Trial, new Vector2(GraphicsDevice.Viewport.Width - font14.MeasureString(Lang.Trial).X - 40,
                    GraphicsDevice.Viewport.Height - 30), Color.White * trial_alpha);
            }

            sprite_batch.End();

            base.Draw(gameTime);
        }

        private void CheckBoardComb()
        {
            for (int i = ROWS_NUMBER - 1; i >= 0; i--)
            {
                for (int j = COLS_NUMBER - 1; j >= 0; j--)
                {
                    if (!tiles[i, j].Picked)
                    {
                        near_tiles.Add(tiles[i, j]);
                        tiles[i, j].Picked = true;

                        for (int k = 0; k < near_tiles.Count; k++)
                            near_tiles.AddRange(near_tiles[k].GetSimilarNeighbours());

                        if (near_tiles.Count >= 5)
                        {
                            dominances[near_tiles[0].Type] += near_tiles.Count * 2.0f;
                            if (dominances[near_tiles[0].Type] > dominances[current_dominance])
                            {
                                current_dominance = near_tiles[0].Type;
                                conversion_timer = 1.2f;
                            }

                            chain_timer += 0.25f + ((difficulty / 2) / 10.0f);

                            game_timer += near_tiles.Count + (current_dominance == near_tiles[0].Type &&
                                dominances[current_dominance] > 6 ? 1 : 0) + (chain_timer > 0.5f ? 1 : 0);

                            var s = ((int)Math.Pow(near_tiles.Count, 1 + (difficulty / 10.0f) + (current_dominance == near_tiles[0].Type && 
                                dominances[current_dominance] > 6 ? 1 : 0) + (chain_timer > 0.5f ? 1 : 0))) + random.Next(10);

                            if (score_timer > 0)
                                current_score += s * 2;
                            else
                                current_score = s;

                            score += s;

                            score_timer = 1.0f;

                            audio_manager.PlayExplosion();

                            ExplodeDropAndReplenishGems();
                        }
                        else
                            for (int k = 0; k < near_tiles.Count; k++)
                                near_tiles[k].Picked = false;

                        near_tiles.Clear();
                    }
                }
            }

            //IntegrityCheck(); 
        }

        private void CheckAndManageHighScores()
        {
            if (high_scores[0] <= current_score)
            {
                high_scores[2] = high_scores[1];
                high_scores[1] = high_scores[0];
                high_scores[0] = current_score;
            }
            else if (high_scores[1] <= current_score && high_scores[0] > current_score)
            {
                high_scores[2] = high_scores[1];
                high_scores[1] = current_score;
            }
            else if (high_scores[2] <= current_score && high_scores[1] > current_score)
                high_scores[2] = current_score;

            current_score = 0;
        }

        private void ChangeExistentValidCombo()
        {
            //recheck = false;
            //for (int i = ROWS_NUMBER - 1; i >= 0; i--)
            //    for (int j = 0; j < COLS_NUMBER; j++)
            //    {
            //        if (!gems[i, j].Picked)
            //        {
            //            near_gem.Add(gems[i, j]);
            //            gems[i, j].Picked = true;

            //            for (int k = 0; k < near_gem.Count; k++)
            //                near_gem.AddRange(near_gem[k].GetSimilarNeighbours());

            //            if (near_gem.Count >= 5)
            //            {
            //                int index = near_gem.Count / 2;

            //                var gem_type = random.Next(8); if (gem_type == near_gem[index].Type) gem_type = (gem_type + random.Next(7)) % 8;

            //                var g = new Gem(this, sprite_batch, Game.Content.Load<Texture2D>("Textures/Game/Tiles/" + gem_type),
            //                    new Vector2(NW_BOARD_COORD.X + CELL_DIM * j, NW_BOARD_COORD.Y + CELL_DIM * i), new Vector2(i, j), gem_type);

            //                gems[g.XCoord, g.YCoord].ChangeGem(g);
            //                gems[near_gem[index].XCoord, near_gem[index].YCoord] = g;

            //                recheck = true;
            //            }
            //            else
            //                for (int k = 0; k < near_gem.Count; k++)
            //                    near_gem[k].Picked = false;
            //        }

            //        near_gem.Clear();
            //    }
        }        

        private void ExplodeDropAndReplenishGems()
        {
            //for (int i = 0; i < combo_list.Count; i++)
            //{
                var ccl = near_tiles;//combo_list[i];

                for (int k = 0; k < ccl.Count; k++)
                {
                    if (!ccl[k].Exploded)
                    {
                        ccl[k].Explode();
                        explosions.AddExplosion(ccl[k].Position, ExplosionType.Normal);
                    }
                }

                for (int k = 0; k < ccl.Count; k++)
                {
                    for (int z = ccl[k].XCoord - 1; z >= 0; z--)
                        if (!tiles[z, ccl[k].YCoord].Moving && !tiles[z, ccl[k].YCoord].Exploded)
                            tiles[z, ccl[k].YCoord].GravityCheck();
                }

                List<Tile> new_tiles = new List<Tile>(7);
                for (int k = 0; k < ccl.Count; k++)
                {
                    for (int z = ROWS_NUMBER - 1; z >= 0; z--)
                        if ((tiles[z, ccl[k].YCoord].IsFalling || tiles[z, ccl[k].YCoord].Exploded) &&
                            !tiles[z, ccl[k].YCoord].Refilled)
                        {
                            var t = tiles[z, ccl[k].YCoord];
                            var new_tile_type = random.Next(8);

                            //System.Diagnostics.Debug.WriteLine("Create new Gem for [" + t.XCoord + "," + t.YCoord + "]");

                            new_tiles.Add(new Tile(this, sprite_batch, Game.Content.Load<Texture2D>("Textures/Game/Tiles/" + new_tile_type),
                                    new Vector2(NW_BOARD_COORD.X + CELL_DIM * t.YCoord, NW_BOARD_COORD.Y - CELL_DIM * (1 + ROWS_NUMBER - t.XCoord)),
                                    new Vector2(NW_BOARD_COORD.X + CELL_DIM * t.YCoord, NW_BOARD_COORD.Y + CELL_DIM * t.XCoord),
                                    new Vector2(t.XCoord, t.YCoord), new_tile_type));

                            t.Refilled = true;
                        }
                }

                for (int k = 0; k < ccl.Count; k++)
                    tiles[ccl[k].XCoord, ccl[k].YCoord].CreateFallingTile(new_tiles[k]);
        }

        private int Distance(Tile t1, Tile t2)
        {
            return Math.Abs(t1.XCoord - t2.XCoord) + Math.Abs(t1.YCoord - t2.YCoord);
        }

        private int FindNearestRotationPoint(Vector2 tpos)
        {
            int index = 0;
            float min_dist = 1000.0f;

            for (int i = 0; i < rotation_points.Count; i++)
            {
                var d = Vector2.Distance(tpos, rotation_points[i].Position);

                if (d < min_dist)
                {
                    min_dist = d;
                    index = i;
                }
            }

            return index;
        }

        private void RotateTiles(int rotation_point_index)
        {
            var r = rotation_points[rotation_point_index];

            var tNE = tiles[(int)r.NE.X, (int)r.NE.Y];
            var tNW = tiles[(int)r.NW.X, (int)r.NW.Y];
            var tSE = tiles[(int)r.SE.X, (int)r.SE.Y];
            var tSW = tiles[(int)r.SW.X, (int)r.SW.Y];

            if (tNE != null && tNW != null && tSE != null && tSW != null && 
                !(tNE.Moving || tNW.Moving || tSE.Moving || tSW.Moving))
            {
                tiles[(int)r.NE.X, (int)r.NE.Y].MoveTo(tiles[(int)r.SE.X, (int)r.SE.Y].Position, r.SE);
                tiles[(int)r.NW.X, (int)r.NW.Y].MoveTo(tiles[(int)r.NE.X, (int)r.NE.Y].Position, r.NE);
                tiles[(int)r.SW.X, (int)r.SW.Y].MoveTo(tiles[(int)r.NW.X, (int)r.NW.Y].Position, r.NW);
                tiles[(int)r.SE.X, (int)r.SE.Y].MoveTo(tiles[(int)r.SW.X, (int)r.SW.Y].Position, r.SW);
            }
        }

        private void GenerateLevelTiles()
        {
            for (int i = 0; i < ROWS_NUMBER; i++)
            {
                for (int j = 0; j < COLS_NUMBER; j++)
                {
                    var tile_type = random.Next(8);
                    
                    var t = new Tile(this, sprite_batch, Game.Content.Load<Texture2D>("Textures/Game/Tiles/" + tile_type), 
                        new Vector2(NW_BOARD_COORD.X + CELL_DIM * j, NW_BOARD_COORD.Y + CELL_DIM * i), new Vector2(i,j), tile_type);

                    tiles_to_draw.Add(t);
                    tiles[i, j] = t;
                }
            }

            //while (recheck)
            //    ChangeExistentValidCombo();
        }

        private void GenerateRotationPoint()
        {
            for (int i = 1; i < ROWS_NUMBER; i++)
            {
                for (int j = 1; j < COLS_NUMBER; j++)
                {
                    rotation_points.Add(new RotationPoint(
                        new Vector2(NW_BOARD_COORD.X + CELL_DIM * j, NW_BOARD_COORD.Y + CELL_DIM * i),
                        new Vector2(i - 1, j), new Vector2(i - 1, j - 1), new Vector2(i, j), new Vector2(i, j - 1)));
                }
            }
        }

        private void MediaStateChanged(object sender, EventArgs e)
        {
            if (MediaPlayer.State == MediaState.Playing)
            {
                audio_manager.StopGingle();
            }
            //else
            //    audio_manager.PlayGingle();            
        }

        #region Proprieties

        public List<Tile> Tiles2Draw
        {
            get { return tiles_to_draw; }
        }

        public Tile[,] Tiles
        {
            get { return tiles; }
        }

        #endregion
    }

    #region Support Class

    public class RotationPoint
    {
        public Vector2 NE, NW, SE, SW;
        public Vector2 Position;

        public RotationPoint(Vector2 position, Vector2 NE, Vector2 NW, Vector2 SE, Vector2 SW)
        {
            this.Position = position;
            this.NE = NE;
            this.NW = NW;
            this.SE = SE;
            this.SW = SW;
        }
    }

    public class Cursor
    {
        private Vector2 position;
        public Texture2D Texture;
        private SpriteBatch sprite_batch;
        private Vector2 half_dim;
        private float alpha;

        public Cursor(SpriteBatch sprite_batch, Vector2 position, Texture2D texture)
        {
            this.sprite_batch = sprite_batch;
            this.position = position;
            this.Texture = texture;

            half_dim = new Vector2(texture.Width / 2.0f - 2.0f, texture.Height / 2.0f);
        }

        public void Draw(GameTime gameTime)
        {
            alpha = Math.Max(0, alpha - (float)gameTime.ElapsedGameTime.TotalSeconds * 2.0f);

            sprite_batch.Draw(Texture, position - half_dim, Color.White * alpha);
        }

        public void ChangePosition(Vector2 position)
        {
            this.position = position;
            alpha = 1.0f;
        }
    }

    #endregion
}
